package com.dd.cloud.user.service.consule.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.cloud.common.constants.*;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.common.interceptor.UserInterceptor;
import com.dd.cloud.common.utils.DateUtils;
import com.dd.cloud.common.vo.LoginInfo;
import com.dd.cloud.user.DTO.tencent.ImSendmsgSinParamReq;
import com.dd.cloud.user.entity.consult.ConsultMedicalRecord;
import com.dd.cloud.user.entity.consult.ConsultSubscribe;
import com.dd.cloud.user.entity.consult.TencentImMsg;
import com.dd.cloud.user.entity.doctor.DoctorSettingService;
import com.dd.cloud.user.entity.doctor.DoctorUser;
import com.dd.cloud.user.entity.doctor.PatientMedCard;
import com.dd.cloud.user.entity.order.OrderPay;
import com.dd.cloud.user.entity.patient.PatientUserComplaint;
import com.dd.cloud.user.entity.pres.PresPrescription;
import com.dd.cloud.user.mapper.consult.ConsultSubscribeMapper;
import com.dd.cloud.user.mq.MQConfig;
import com.dd.cloud.user.mq.RabbitSend;
import com.dd.cloud.user.req.consult.*;
import com.dd.cloud.user.req.order.CreateOrderReq;
import com.dd.cloud.user.res.chat.ConsultDoctorPageRes;
import com.dd.cloud.user.res.chat.InquiryDateQueueRes;
import com.dd.cloud.user.res.consult.*;
import com.dd.cloud.user.res.doctor.PatientMedCardDetailRes;
import com.dd.cloud.user.res.order.PayOrderResponse;
import com.dd.cloud.user.service.consule.IConsultMedicalRecordService;
import com.dd.cloud.user.service.consule.IConsultSubscribeService;
import com.dd.cloud.user.service.consule.ITencentImMsgService;
import com.dd.cloud.user.service.doctor.IDoctorDetailService;
import com.dd.cloud.user.service.doctor.IDoctorSettingServiceService;
import com.dd.cloud.user.service.doctor.IDoctorUserService;
import com.dd.cloud.user.service.doctor.IPatientMedCardService;
import com.dd.cloud.user.service.log.ILogErrorService;
import com.dd.cloud.user.service.order.IOrderPayService;
import com.dd.cloud.user.service.patient.IPatientUserComplaintService;
import com.dd.cloud.user.service.patient.IPatientUserService;
import com.dd.cloud.user.service.pres.IPresPrescriptionService;
import com.dd.cloud.user.service.search.ISearchHistoryService;
import com.dd.cloud.user.vo.DelayMqVo;
import com.zk.pay.constants.CS;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 预约问诊表 服务实现类
 * </p>
 *
 * @author czg
 * @since 2023-07-07
 */
@Service
@Slf4j
public class ConsultSubscribeServiceImpl extends ServiceImpl<ConsultSubscribeMapper, ConsultSubscribe> implements IConsultSubscribeService {
    @Autowired
    private ISearchHistoryService searchHistoryService;
    @Autowired
    private IPatientMedCardService patientMedCardService;
    @Autowired
    private IDoctorUserService doctorUserService;
    @Autowired
    private IDoctorDetailService doctorDetailService;
    @Autowired
    private IDoctorSettingServiceService doctorSettingServiceService;
    @Autowired
    private IOrderPayService orderPayService;
    @Autowired
    private ILogErrorService logErrorService;
    @Autowired
    private RabbitSend rabbitSend;
    @Autowired
    private ITencentImMsgService tencentImMsgService;
    @Autowired
    private IConsultMedicalRecordService consultMedicalRecordService;

    @Autowired
    private IPatientUserComplaintService patientUserComplaintService;

    @Autowired
    private IPresPrescriptionService presPrescriptionService;
    @Autowired
    private IPatientUserService patientUserService;

    /**
     * @param :
     * @return List<InquiryDateQueueRes>
     * @description 查询预约问诊排班
     * @author czg
     * @date 2023/7/8 14:58
     */
    @Override
    public List<InquiryDateQueueRes> inquiryScheduling() {
        LocalDate date = LocalDate.now().plusDays(14);
        List<InquiryDateQueueRes> res = getBaseMapper().inquiryScheduling(date);
        if (res != null && !res.isEmpty()) {
            res = res.stream().map(item -> {
                item.setSimpleDay(item.getDay().substring(item.getDay().indexOf("-") + 1));
                return item;
            }).collect(Collectors.toList());
        }
        return res;
    }

    /**
     * @param :
     * @return List<InquiryDateQueueRes>
     * @description 查询预约咨询排班
     * @author czg
     * @date 2023/7/8 14:57
     */
    @Override
    public List<InquiryDateQueueRes> consultScheduling() {
        LocalDate date = LocalDate.now().plusDays(14);
        List<InquiryDateQueueRes> res = getBaseMapper().consultScheduling(date);
        if (res != null && !res.isEmpty()) {
            res = res.stream().map(item -> {
                item.setSimpleDay(item.getDay().substring(item.getDay().indexOf("-") + 1));
                return item;
            }).collect(Collectors.toList());
        }

        return res;
    }

    /**
     * @param :
     * @return List<InquiryDoctorListRes>
     * @description 查询问诊医生列表
     * @author czg
     * @date 2023/7/8 15:58
     */
    @Override
    public Page<ConsultDoctorPageRes> consultDoctorList(ConsultDoctorPageReq req) {
        Page<ConsultDoctorPageRes> page = req.pagePojo();
        if (!StringUtils.isBlank(req.getKeyword())) {
            //有搜索, 添加搜索历史
            searchHistoryService.addSearchHistory(req.getKeyword(), SearchConstants.Modular.CONSULT);
        }
        return getBaseMapper().consultDoctorList(page, req);
    }

    /**
     * @param req:
     * @return PayOrderResponse<?> 返回支付信息
     * @description 患者预约咨询医生
     * @author czg
     * @date 2023/7/11 15:04
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayOrderResponse<?> consultSubmit(HttpServletRequest request, ConsultSubscribeCreateReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        if (loginInfo.getType() != LoginInfo.UserType.PATIENT) {
            throw new ZekeException("只有患者能预约");
        }

        if (ConsultConstants.Type.INQUIRY == req.getType() && req.getVisitType() == null) {
            throw new ZekeException("健康问诊请选择是否复诊");
        }
        if (ConsultConstants.Type.INQUIRY == req.getType() && req.getVisitType() == 1 && StringUtils.isBlank(req.getFirstMechanName())) {
            throw new ZekeException("请输入机构名称");
        }
        DoctorUser doctorUser = doctorUserService.getById(req.getDoctorId());
        if (doctorUser == null || doctorUser.getStatus() == UserConstants.DoctorUserStatus.LOGOFF || doctorUser.getStatus() == UserConstants.DoctorUserStatus.DEL) {
            throw new ZekeException("医生不存在");
        }

        QueryWrapper<PatientMedCard> qw = new QueryWrapper<>();
        qw.lambda().eq(PatientMedCard::getMedId, req.getMedId()).eq(PatientMedCard::getStatus, UserConstants.MedCardStatus.NORMAL);
        PatientMedCard one = patientMedCardService.getOne(qw);
        if (one == null) {
            throw new ZekeException("就诊卡号不存在");
        }
        QueryWrapper<DoctorSettingService> ws = new QueryWrapper<>();
        ws.lambda().eq(DoctorSettingService::getDoctorId, req.getDoctorId());
        DoctorSettingService serviceServiceOne = doctorSettingServiceService.getOne(ws);
        if (serviceServiceOne == null) {
            throw new ZekeException("医生咨询问诊内容为空");
        }
        QueryWrapper<ConsultSubscribe> qq = new QueryWrapper<>();
        qq.lambda().eq(ConsultSubscribe::getDoctorId, req.getDoctorId()).eq(ConsultSubscribe::getPatientId, loginInfo.getId()).eq(ConsultSubscribe::getMedId, req.getMedId()).and(t -> {
            t.eq(ConsultSubscribe::getStatus, ConsultConstants.Status.SUBMIT).or().eq(ConsultSubscribe::getStatus, ConsultConstants.Status.UNDERWAY);
        });
        List<ConsultSubscribe> list = list(qq);
        if (null != list && !list.isEmpty()) {
            throw new ZekeException("您已预约该医生，不可重复预约");
        }

        //计算预约量
        QueryWrapper<ConsultSubscribe> qt = new QueryWrapper<>();
        qt.lambda().eq(ConsultSubscribe::getDoctorId, req.getDoctorId()).eq(ConsultSubscribe::getType, req.getType()).ne(ConsultSubscribe::getStatus, ConsultConstants.Status.CANCEL).ge(ConsultSubscribe::getCreateDate, DateUtils.getStartTimeOfDay(LocalDate.now()));
        int count = count(qt);
        if (ConsultConstants.Type.INQUIRY == req.getType()) {
            if (serviceServiceOne.getIsOpenInquiry() == UserConstants.IsOpenSetting.NO) {
                throw new ZekeException("医生未开启问诊服务, 不能预约");
            }
            if (count >= serviceServiceOne.getInquiryNum()) {
                throw new ZekeException("医生问诊今天已约满,请换医生预约");
            }
            if (!req.getConsultPrice().equals(serviceServiceOne.getInquiryPrice())) {
                throw new ZekeException("金额有误");
            }
        }
        if (ConsultConstants.Type.CONSULT == req.getType()) {
            if (serviceServiceOne.getIsOpenConsult() == UserConstants.IsOpenSetting.NO) {
                throw new ZekeException("医生未开启咨询服务, 不能预约");
            }
            if (count >= serviceServiceOne.getConsultNum()) {
                throw new ZekeException("医生问诊今天已约满,请换医生预约");
            }
            if (!req.getConsultPrice().equals(serviceServiceOne.getConsultPrice())) {
                throw new ZekeException("金额有误");
            }
        }
        ConsultSubscribe consultSubscribe = new ConsultSubscribe();
        BeanUtils.copyProperties(req, consultSubscribe);
        consultSubscribe.setPatientPhone(one.getMobileNumber());
        consultSubscribe.setPatientName(one.getName());
//        consultSubscribe.setPatientAge(CalendarUtil.getAge(one.getBirthDate()));
        consultSubscribe.setPatientBirthDate(one.getBirthDate());
        consultSubscribe.setPatientSex(one.getSex());
        consultSubscribe.setPatientNationality(one.getNationality());
        consultSubscribe.setPatientPregnant(one.getPregnant());
        consultSubscribe.setPatientMaritalStatus(one.getMaritalStatus());
        consultSubscribe.setCreateDate(LocalDateTime.now());
        consultSubscribe.setStatus(ConsultConstants.Status.NOPAY);
        consultSubscribe.setPatientId(loginInfo.getId());
        consultSubscribe.setEndDate(DateUtils.todayEndTime(consultSubscribe.getDay()));
        int insert = getBaseMapper().insert(consultSubscribe);
        if (insert <= 0) {
            throw new ZekeException("预约添加失败");
        }

        /*
         * 创建支付订单
         */
        CreateOrderReq orderReq = new CreateOrderReq();
        orderReq.setOpenid(req.getOpenId());
        orderReq.setPayType(req.getPayType());
        orderReq.setPrice(serviceServiceOne.getConsultPrice());
        if (ConsultConstants.Type.INQUIRY == req.getType()) {
            orderReq.setPrice(serviceServiceOne.getInquiryPrice());
        }
        orderReq.setServerNo(String.valueOf(consultSubscribe.getId()));
        orderReq.setPartyId(0);
        orderReq.setPartyType(1);
        orderReq.setApply("applet");
        orderReq.setProduct(CS.NOTICE_CHANNEL.SINGLE);
        // 5 为生成问诊订单号编码类型
        PayOrderResponse<?> res = orderPayService.createOrder(request, orderReq, 5);
        res.setConsultId(consultSubscribe.getId());
        //订单过期定时器
        DelayMqVo<String> delayMqVo = new DelayMqVo<>();
        delayMqVo.setT(String.valueOf(consultSubscribe.getId()));
        delayMqVo.setType(DelayMqVo.DelayMqVoType.CONSULT_TIMEOUT);
        //毫秒级 15min消息
        long ms = 1000 * 60 * 15;
        rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo, ms);
        //毫秒级 5min消息
        DelayMqVo<String> delayMqVo1 = new DelayMqVo<>();
        delayMqVo1.setT(res.getOrderPay().getOrderNo() + "-10分钟");
        delayMqVo1.setType(DelayMqVo.DelayMqVoType.INQUIRY_ORDER_REMIND);
        long ms1 = 1000 * 60 * 5;
        rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo1, ms1);
        //毫秒级 10min消息
        DelayMqVo<String> delayMqVo2 = new DelayMqVo<>();
        delayMqVo2.setT(res.getOrderPay().getOrderNo() + "-5分钟");
        delayMqVo2.setType(DelayMqVo.DelayMqVoType.INQUIRY_ORDER_REMIND);
        long ms2 = 1000 * 60 * 10;
        rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo2, ms2);
        return res;
    }

    @Override
    public IPage<UserInfoRes> queryImTencent(ImTencentRecordReq req) {
//        LambdaQueryWrapper<TencentImMsg> wrapper = new LambdaQueryWrapper<>();
//        wrapper.eq(TencentImMsg::getConsultId, req.getId()).orderByAsc(TencentImMsg::getCreateDate);
        IPage<UserInfoRes> page = req.pagePojo();
        IPage<UserInfoRes> res = this.getBaseMapper().queryImTencent(page, req.getId());
        return res;
    }

    /**
     * @param req:
     * @return Page<ConsultSubscribePageRes>
     * @description 患者查询预约记录
     * @author czg
     * @date 2023/7/14 9:46
     */
    @Override
    public Page<ConsultSubscribePageRes> consultPage(ConsultSubscribePageReq req) {
        if (StringUtils.isBlank(req.getStatus())) {
            req.setStatus("-2,-1,0,1,3,4,5,6,7");
        }
        if (!StringUtils.isBlank(req.getStatus())) {
            req.setStatusStr(req.getStatus().split(","));
        }
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.PATIENT).get();
        req.setId(loginInfo.getId());
        Page<ConsultSubscribePageRes> page = req.pagePojo();
        page = getBaseMapper().consultPage(page, req);
        getImRecord(page);
        return page;
    }

    private void getImRecord(Page<ConsultSubscribePageRes> page) {
        if (CollectionUtils.isNotEmpty(page.getRecords())) {
            for (ConsultSubscribePageRes res : page.getRecords()) {
                LambdaQueryWrapper<PresPrescription> qw = new LambdaQueryWrapper<>();
                qw.eq(PresPrescription::getConsultId, res.getId()).orderByDesc(PresPrescription::getCreateDate).last("limit 1");
                PresPrescription presPrescription = presPrescriptionService.getOne(qw);
                if (presPrescription != null) {
                    res.setTencode(presPrescription.getTencode());
                }
                LambdaQueryWrapper<TencentImMsg> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(TencentImMsg::getConsultId, res.getId()).in(TencentImMsg::getStatus, 0, 1, 2).orderByDesc(TencentImMsg::getCreateDate).last("limit 1");
                TencentImMsg tencentImMsg = tencentImMsgService.getOne(wrapper);
                LambdaQueryWrapper<TencentImMsg> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(TencentImMsg::getConsultId, res.getId()).in(TencentImMsg::getStatus, 1)
                        .eq(TencentImMsg::getToUser, res.getPatientId()).eq(TencentImMsg::getToUserType, 6)
                        .orderByDesc(TencentImMsg::getCreateDate)
                        .last("limit 1");
                TencentImMsg tencentImMsg1 = tencentImMsgService.getOne(queryWrapper);
                if (tencentImMsg != null) {
                    if (tencentImMsg1 != null) {
                        tencentImMsg.setStatus(tencentImMsg1.getStatus());
                    } else {
                        tencentImMsg.setStatus(2);
                    }
                }
                res.setTencentImMsg(tencentImMsg);
                //是否有电子病例
                LambdaQueryWrapper<ConsultMedicalRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                lambdaQueryWrapper.eq(ConsultMedicalRecord::getStatus, ConsultConstants.ConsultMedicalRecordStatus.NORMAL)
                        .eq(ConsultMedicalRecord::getConsultId, res.getId());
                Integer count = consultMedicalRecordService.count(lambdaQueryWrapper);
                if (count > 0) {
                    res.setIsHave(1);
                } else {
                    res.setIsHave(0);
                }
            }
        }
    }

    /**
     * @param id:
     * @return ConsultSubscribeDetailRes
     * @description 患者查询预约详情
     * @author czg
     * @date 2023/7/14 10:16
     */
    @Override
    public ConsultSubscribeDetailRes consultDetail(Integer id) {
        ConsultSubscribeDetailRes consultDetail = getBaseMapper().consultDetail(id);
        LambdaQueryWrapper<PatientUserComplaint> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PatientUserComplaint::getConsultId, id).orderByDesc(PatientUserComplaint::getCreateDate).last("limit 1");
        PatientUserComplaint patientUserComplaint = patientUserComplaintService.getOne(wrapper);
        ConsultMedicalRecordDetailRes res = consultMedicalRecordService.queryConsultMedicalRecordDetail(id);
        if (consultDetail != null) {
            consultDetail.setPatientUserComplaint(patientUserComplaint);
            if (res != null) {
                consultDetail.setMedicalId(res.getId());
                consultDetail.setMedicalStatus(res.getStatus());
            }
        }
        LambdaQueryWrapper<PresPrescription> qw = new LambdaQueryWrapper<>();
        qw.eq(PresPrescription::getConsultId, id).orderByDesc(PresPrescription::getCreateDate).last("limit 1");
        PresPrescription presPrescription = presPrescriptionService.getOne(qw);
        if (presPrescription != null) {
            if (consultDetail != null) {
                consultDetail.setTencode(presPrescription.getTencode());
            }
        }
        return consultDetail;
    }

    /**
     * @param id: 预约的id
     * @return void
     * @description 预约订单过期处理
     * @author czg
     * @date 2023/7/14 14:11
     */
    @Override
    public void consultOrderTimeout(Integer id) {
        ConsultSubscribe subscribe = getById(id);
        if (subscribe == null) {
            logErrorService.presBackLog("预约订单过期,预约id不存在", "延时队列执行数据异常", "id=" + id);
            return;
        }
        QueryWrapper<OrderPay> qw = new QueryWrapper<>();
        qw.lambda().eq(OrderPay::getServerNo, id).eq(OrderPay::getProduct, CS.NOTICE_CHANNEL.SINGLE);
        OrderPay orderPay = orderPayService.getOne(qw);
        if (orderPay == null) {
            logErrorService.presBackLog("预约订单过期,订单编号不存在", "延时队列执行数据异常", "id=" + id);
            return;
        }
        //不是未支付状态,不处理
        if (orderPay.getStatus() != OrderConstants.Status.NOPAY) {
            return;
        }
        orderPay.setStatus(OrderConstants.Status.TIMEOUT);
        //取消时间
        orderPay.setUpdateDate(LocalDateTime.now());
        boolean updateById = orderPayService.updateById(orderPay);
        if (!updateById) {
            logErrorService.presBackLog("预约订单过期,修改订单失败", "延时队列执行数据异常", "orderNO=" + orderPay.getOrderNo());
            return;
        }
        subscribe.setStatus(ConsultConstants.Status.CANCEL);
        subscribe.setRemark("订单超时关闭");
        boolean update = updateById(subscribe);
        if (!update) {
            logErrorService.presBackLog("预约订单过期,修改预约表失败", "延时队列执行数据异常", "id=" + id);
        }
    }

    /**
     * 医生查询患者预约记录
     *
     * @param req
     * @return
     */
    @Override
    public IPage<ConsultSubscribeDoctorPageRes> queryConsultSubscribeDoctorPage(ConsultSubscribeDoctorPageReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.DOCTOR).get();
        req.setDoctorId(loginInfo.getId());
        if (StringUtils.isBlank(req.getStatus())) {
            req.setStatus(ConsultConstants.Status.DOCTOR_CAN_QUE);
        }
        IPage<ConsultSubscribeDoctorPageRes> iPage = req.pagePojo();
        iPage = getBaseMapper().queryConsultSubscribeDoctorPage(iPage, req);
        return iPage;
    }

    /**
     * 医生接诊
     *
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void receivePatientSubscribe(Integer id) {
//        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.DOCTOR).get();
        ConsultSubscribe subscribe = getById(id);
        if (subscribe == null) {
            throw new ZekeException(400, "问诊记录申请不存在");
        }
//        if (!subscribe.getDoctorId().equals(subscribe.getDoctorId())) {
//            throw new ZekeException(400, "无法接诊其他医生问诊");
//        }
        if (!subscribe.getDay().equals(LocalDate.now())) {
            throw new ZekeException(400, "请于" + subscribe.getDay().format(DateUtils.DTF_YMD) + "当日接诊，暂不支持提前接单。");
        }
        if (subscribe.getStatus() != ConsultConstants.Status.SUBMIT) {
            throw new ZekeException(400, "问诊记录未在待接诊状态");
        }
        ConsultSubscribe update = new ConsultSubscribe();
        update.setId(id);
        update.setStatus(ConsultConstants.Status.UNDERWAY);
        update.setStartDate(LocalDateTime.now());
        update.setEndDate(update.getStartDate().plusHours(24));
        boolean flag = updateById(update);
        if (!flag) {
            throw new ZekeException(400, "接诊失败");
        }
        DelayMqVo<String> delayMqVo1 = new DelayMqVo<>();
        delayMqVo1.setT(String.valueOf(id));
        delayMqVo1.setType(DelayMqVo.DelayMqVoType.CONSULT_AUTO_COMPLETE);
        // 毫秒级延时 24小时
        long delay1 = 1000 * 60 * 60 * 24;
        rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo1, delay1);
        log.info("发送自动结束问诊延迟消息");

        DelayMqVo<String> delayMqVo2 = new DelayMqVo<>();
        delayMqVo2.setT(String.valueOf(id));
        delayMqVo2.setType(DelayMqVo.DelayMqVoType.CONSULT_PATIENT_NOT_REPLY);
        //毫秒级 5分钟
        long delay2 = 1000 * 60 * 5;
        rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo2, delay2);
        log.info("发送问诊开始患者未响应延迟消息");
        //毫秒级 30分钟
        long delay = 1000 * 60 * 30;
        rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo2, delay);
    }

    /**
     * 医生结束问诊
     *
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completePatientSubscribe(Integer id) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.DOCTOR).get();
        ConsultSubscribe subscribe = getById(id);
        if (subscribe == null) {
            throw new ZekeException(400, "问诊记录申请不存在");
        }
        if (!subscribe.getDoctorId().equals(loginInfo.getId())) {
            throw new ZekeException(400, "无法结束其他医生问诊");
        }
        if (subscribe.getStatus() != ConsultConstants.Status.UNDERWAY) {
            throw new ZekeException(400, "问诊记录未在进行中状态,无法结束问诊");
        }
        ConsultSubscribe update = new ConsultSubscribe();
        update.setId(id);
        update.setStatus(ConsultConstants.Status.SUCCWAITEVAL);
        update.setEndDate(LocalDateTime.now());
        boolean flag = updateById(update);
        if (!flag) {
            throw new ZekeException(400, "结束问诊失败");
        }
        //发送结束通知, 并提示评价
        ImSendmsgSinParamReq imSendmsgSinParamReq = new ImSendmsgSinParamReq();
        imSendmsgSinParamReq.setFrom_Account(subscribe.getDoctorId() + "_" + LoginInfo.UserType.DOCTOR);
        imSendmsgSinParamReq.setTo_Account(subscribe.getPatientId() + "_" + LoginInfo.UserType.PATIENT + "_" + subscribe.getMedId());
        imSendmsgSinParamReq.setSyncOtherMachine(1);
        imSendmsgSinParamReq.setCloudCustomData(String.valueOf(subscribe.getId()));
        TencentConstants.ImMsgPojo imMsgPojo = new TencentConstants.ImMsgPojo();
        tencentImMsgService.imSendmsgSymtem(imSendmsgSinParamReq, imMsgPojo.imMsgSet(TencentConstants.ImMsgCustom.CONSULTOVER));

        imSendmsgSinParamReq = new ImSendmsgSinParamReq();
        imSendmsgSinParamReq.setFrom_Account(subscribe.getPatientId() + "_" + LoginInfo.UserType.PATIENT + "_" + subscribe.getMedId());
        imSendmsgSinParamReq.setTo_Account(subscribe.getDoctorId() + "_" + LoginInfo.UserType.DOCTOR);
        imSendmsgSinParamReq.setSyncOtherMachine(2);
        imSendmsgSinParamReq.setCloudCustomData(String.valueOf(subscribe.getId()));
        imMsgPojo = new TencentConstants.ImMsgPojo();
        if (subscribe.getType() == 1) {
            tencentImMsgService.imSendmsgSymtem(imSendmsgSinParamReq, imMsgPojo.imMsgSet(TencentConstants.ImMsgCustom.DOCTOR_END_1));
        } else {
            tencentImMsgService.imSendmsgSymtem(imSendmsgSinParamReq, imMsgPojo.imMsgSet(TencentConstants.ImMsgCustom.DOCTOR_END_2));
        }


        ConsultMedicalRecordDetailRes res = consultMedicalRecordService.queryConsultMedicalRecordDetail(subscribe.getId());
        if (subscribe.getType() == 1 && res != null && res.getId() == null) {
            imSendmsgSinParamReq = new ImSendmsgSinParamReq();
            imSendmsgSinParamReq.setFrom_Account(subscribe.getPatientId() + "_" + LoginInfo.UserType.PATIENT + "_" + subscribe.getMedId());
            imSendmsgSinParamReq.setTo_Account(subscribe.getDoctorId() + "_" + LoginInfo.UserType.DOCTOR);
            imSendmsgSinParamReq.setSyncOtherMachine(2);
            imSendmsgSinParamReq.setCloudCustomData(String.valueOf(subscribe.getId()));
            imMsgPojo = new TencentConstants.ImMsgPojo();
            tencentImMsgService.imSendmsgSymtem(imSendmsgSinParamReq, imMsgPojo.imMsgSet(TencentConstants.ImMsgCustom.DOCTOR_END_MEDICAL));
        }

        /**
         * 订单结束7天后进行分账设置
         */
        DelayMqVo<String> delayMqVo = new DelayMqVo<>();
        delayMqVo.setT(id + "-" + subscribe.getDoctorId());
        delayMqVo.setType(DelayMqVo.DelayMqVoType.CONSULT_ORDER_SETTING);
        //毫秒级 seconds秒
        long delay = 7 * 24 * 60 * 60 * 1000;
        rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo, delay);
        /**
         * 发送待评价模板消息
         */
        String params = TemplateConstants.TemplateType.FIVE_TYPE + "-" + id;
        log.info("问诊结束发送评价通知模板,参数为{}", params);
        rabbitSend.sendMessage(MQConfig.TEMPLATE_EXCHANGE, MQConfig.TEMPLATE_QUEUE, params);
    }

    /**
     * 延迟问诊时长 参数分钟
     *
     * @param id
     * @param min
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public LocalDateTime patientSubscribeDelayed(Integer id, Integer min) {
        if (min != 10 && min != 20 && min != 30 && min != 40 && min != 50 && min != 60) {
            throw new ZekeException(400, "只支持延长10、20、30、40、50、60分钟");
        }
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.DOCTOR).get();
        ConsultSubscribe subscribe = getById(id);
        if (subscribe == null) {
            throw new ZekeException(400, "问诊记录申请不存在");
        }
        if (!subscribe.getDoctorId().equals(loginInfo.getId())) {
            throw new ZekeException(400, "无法延长其他医生问诊时长");
        }
        if (subscribe.getStatus() != ConsultConstants.Status.UNDERWAY) {
            throw new ZekeException(400, "问诊记录未在进行中状态,无法延迟问诊时长");
        }
        ConsultSubscribe update = new ConsultSubscribe();
        update.setId(id);
        update.setEndDate(subscribe.getEndDate().plusMinutes(min));
        update.setDelayMinutes(min);
        boolean flag = updateById(update);
        if (!flag) {
            throw new ZekeException(400, "延迟问诊时长失败");
        }
        long seconds = ChronoUnit.SECONDS.between(LocalDateTime.now(), update.getEndDate());
        DelayMqVo<String> delayMqVo = new DelayMqVo<>();
        delayMqVo.setT(String.valueOf(id));
        delayMqVo.setType(DelayMqVo.DelayMqVoType.CONSULT_AUTO_COMPLETE);
        //毫秒级 seconds秒
        long delay = 1000 * seconds;
        rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo, delay);
        return update.getEndDate();
    }

    /**
     * @param :
     * @return void
     * @description 预约自动结束 发送提示评价im消息
     * @author czg
     * @date 2023/7/19 15:28
     */
    @Override
    public void consultAutoFinish() {
        LocalDate endDate = LocalDate.now().plusDays(-1);
        LocalDateTime endTime = DateUtils.todayEndTime(endDate);
        QueryWrapper<ConsultSubscribe> qw = new QueryWrapper<>();
        qw.lambda().eq(ConsultSubscribe::getEndDate, endTime).eq(ConsultSubscribe::getStatus, ConsultConstants.Status.UNDERWAY);
        List<ConsultSubscribe> list = list(qw);
        if (list == null || list.isEmpty()) {
            return;
        }
        list.forEach(item -> {
            item.setStatus(ConsultConstants.Status.SUCCWAITEVAL);
            boolean flag = updateById(item);
            if (flag) {
                //发送结束通知, 并提示评价
                ImSendmsgSinParamReq imSendmsgSinParamReq = new ImSendmsgSinParamReq();
                imSendmsgSinParamReq.setFrom_Account(item.getDoctorId() + "_" + LoginInfo.UserType.DOCTOR);
                imSendmsgSinParamReq.setTo_Account(item.getPatientId() + "_" + LoginInfo.UserType.PATIENT + "_" + item.getMedId());
                imSendmsgSinParamReq.setSyncOtherMachine(1);
                imSendmsgSinParamReq.setCloudCustomData(String.valueOf(item.getId()));
                TencentConstants.ImMsgPojo imMsgPojo = new TencentConstants.ImMsgPojo();
                tencentImMsgService.imSendmsgSymtem(imSendmsgSinParamReq, imMsgPojo.imMsgSet(TencentConstants.ImMsgCustom.CONSULTOVER));

            }
        });
    }

    /**
     * 预约待接诊,未接诊自动超时,退款
     */
    @Override
    public void consultAutoSubmitTimeout() {
        LocalDate endDate = LocalDate.now().plusDays(-1);
        LocalDateTime endTime = DateUtils.todayEndTime(endDate);
        QueryWrapper<ConsultSubscribe> qw = new QueryWrapper<>();
        qw.lambda().eq(ConsultSubscribe::getEndDate, endTime).eq(ConsultSubscribe::getStatus, ConsultConstants.Status.SUBMIT);
        List<ConsultSubscribe> list = list(qw);
        if (list == null || list.isEmpty()) {
            return;
        }
        list.forEach(item -> {
            ConsultSubscribe update = new ConsultSubscribe();
            update.setStatus(ConsultConstants.Status.SUBMIT_TIMEOUT);
            boolean flag = updateById(update);
            if (flag) {
                orderPayService.refund(orderPayService.queryOrderNoByServerNo(item.getId().toString()), 0);
            }
        });
    }

    /**
     * 预约自动完成
     *
     * @param id
     */
    @Override
    public void consultAutoComplete(Integer id) {
        log.info("问诊id:{}", id);
        ConsultSubscribe subscribe = getById(id);
        if (subscribe == null) {
            log.info("未查到问诊数据返回");
            return;
        }
        if (subscribe.getStatus() != ConsultConstants.Status.UNDERWAY) {
            log.info("问诊数据未在进行中返回");
            return;
        }
        long seconds = ChronoUnit.SECONDS.between(subscribe.getEndDate(), LocalDateTime.now());
        log.info("问诊自动结束结束时间与现在时间之差:{}", seconds);
        if (seconds < -1) {
            return;
        }
        ConsultSubscribe update = new ConsultSubscribe();
        update.setId(id);
        update.setStatus(ConsultConstants.Status.SUCCWAITEVAL);
        boolean flag = updateById(update);
        if (flag) {
            //发送结束通知, 并提示评价
            ImSendmsgSinParamReq imSendmsgSinParamReq = new ImSendmsgSinParamReq();
            imSendmsgSinParamReq.setFrom_Account(subscribe.getDoctorId() + "_" + LoginInfo.UserType.DOCTOR);
            imSendmsgSinParamReq.setTo_Account(subscribe.getPatientId() + "_" + LoginInfo.UserType.PATIENT + "_" + subscribe.getMedId());
            imSendmsgSinParamReq.setSyncOtherMachine(1);
            imSendmsgSinParamReq.setCloudCustomData(String.valueOf(subscribe.getId()));
            TencentConstants.ImMsgPojo imMsgPojo = new TencentConstants.ImMsgPojo();
            tencentImMsgService.imSendmsgSymtem(imSendmsgSinParamReq, imMsgPojo.imMsgSet(TencentConstants.ImMsgCustom.CONSULTOVER));

            imSendmsgSinParamReq = new ImSendmsgSinParamReq();
            imSendmsgSinParamReq.setFrom_Account(subscribe.getPatientId() + "_" + LoginInfo.UserType.PATIENT + "_" + subscribe.getMedId());
            imSendmsgSinParamReq.setTo_Account(subscribe.getDoctorId() + "_" + LoginInfo.UserType.DOCTOR);
            imSendmsgSinParamReq.setSyncOtherMachine(2);
            imSendmsgSinParamReq.setCloudCustomData(String.valueOf(subscribe.getId()));
            imMsgPojo = new TencentConstants.ImMsgPojo();
            if (subscribe.getType() == 1) {
                tencentImMsgService.imSendmsgSymtem(imSendmsgSinParamReq, imMsgPojo.imMsgSet(TencentConstants.ImMsgCustom.DOCTOR_END_1));
            } else {
                tencentImMsgService.imSendmsgSymtem(imSendmsgSinParamReq, imMsgPojo.imMsgSet(TencentConstants.ImMsgCustom.DOCTOR_END_2));
            }

            ConsultMedicalRecordDetailRes res = consultMedicalRecordService.queryConsultMedicalRecordDetail(subscribe.getId());
            if (subscribe.getType() == 2 && res != null && res.getId() == null) {
                imSendmsgSinParamReq = new ImSendmsgSinParamReq();
                imSendmsgSinParamReq.setFrom_Account(subscribe.getPatientId() + "_" + LoginInfo.UserType.PATIENT + "_" + subscribe.getMedId());
                imSendmsgSinParamReq.setTo_Account(subscribe.getDoctorId() + "_" + LoginInfo.UserType.DOCTOR);
                imSendmsgSinParamReq.setSyncOtherMachine(2);
                imSendmsgSinParamReq.setCloudCustomData(String.valueOf(subscribe.getId()));
                imMsgPojo = new TencentConstants.ImMsgPojo();
                tencentImMsgService.imSendmsgSymtem(imSendmsgSinParamReq, imMsgPojo.imMsgSet(TencentConstants.ImMsgCustom.DOCTOR_END_MEDICAL));
            }

            /**
             * 订单结束7天后进行分账设置
             */
            DelayMqVo<String> delayMqVo = new DelayMqVo<>();
            delayMqVo.setT(id + "-" + subscribe.getDoctorId());
            delayMqVo.setType(DelayMqVo.DelayMqVoType.CONSULT_ORDER_SETTING);
            //毫秒级 seconds秒
            long delay = 7 * 24 * 60 * 60 * 1000;
            rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo, delay);
            /**
             * 发送待评价模板消息
             */
            String params = TemplateConstants.TemplateType.FIVE_TYPE + "-" + id;
            log.info("问诊结束发送评价通知模板,参数为{}", params);
            rabbitSend.sendMessage(MQConfig.TEMPLATE_EXCHANGE, MQConfig.TEMPLATE_QUEUE, params);
        }
    }

    /**
     * 问诊医生接诊未回复发送短信
     *
     * @param id
     */
    @Override
    public void consultPatientNotReply(Integer id) {
        log.info("问诊id:{}", id);
        ConsultSubscribe subscribe = getById(id);
        if (subscribe == null) {
            log.info("未查到问诊数据返回");
            return;
        }
        QueryWrapper<TencentImMsg> qw = new QueryWrapper<>();
        qw.lambda().eq(TencentImMsg::getConsultId, id);
        qw.lambda().eq(TencentImMsg::getFromUserType, LoginInfo.UserType.PATIENT);
        qw.lambda().ne(TencentImMsg::getStatus, TencentConstants.ImMsgStatus.FAIL);
        int count = tencentImMsgService.count(qw);
        if (count == 0) {
            PatientMedCardDetailRes res = patientMedCardService.queryPatientMedCardDetail(subscribe.getMedId());
            Map<String, String> msg = new HashMap<>(5);
            msg.put("phone", res.getMobileNumber());
            msg.put("name", res.getName());
            msg.put("date", DateUtils.DTF_YMD.format(subscribe.getDay()));
            msg.put("param_type", SmsConstants.ParamType.JSON);
            msg.put("sms_template", SmsConstants.Template.INTERFLOW_NOT_REPLY);
            rabbitSend.sendMessage(MQConfig.SMS_EXCHANGE, MQConfig.SMS_KEY, msg);
            DelayMqVo<String> delayMqVo = new DelayMqVo<>();
            delayMqVo.setT(String.valueOf(id));
            delayMqVo.setType(DelayMqVo.DelayMqVoType.CONSULT_PATIENT_NOT_REPLY);
        }
    }

    /**
     * 查询患者电子病例
     *
     * @param consultId
     * @return
     */
    @Override
    public ConsultMedicalRecordDetailRes queryMedicalRecord(Integer consultId) {
        ConsultMedicalRecordDetailRes medicalDetailRes = consultMedicalRecordService.queryConsultMedicalRecordDetail(consultId);
        return medicalDetailRes;
    }

    /**
     * 查询医生待办消息
     *
     * @param doctorId
     * @return
     */
    @Override
    public ConsultMsgUnReadCountRes queryConsultMsgUnReadCountDoctor(Integer doctorId) {
        if (doctorId == null) {
            doctorId = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.DOCTOR).get().getId();
        }
        return getBaseMapper().queryConsultMsgUnReadCountDoctor(doctorId);
    }


    /**
     * 用户未读数
     */
    @Override
    public ConsultMsgUnReadCountRes queryConsultMsgUnReadCountUser() {
        Integer userId = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.PATIENT).get().getId();
        return getBaseMapper().queryConsultMsgUnReadCountUser(userId);
    }

    /**
     * 问诊中处方订单支付成功通知消息
     *
     * @param consultId
     */
    @Override
    public void consultPresPaySuccess(Integer consultId) {
        ConsultSubscribe cs = getById(consultId);
        if (cs != null) {
            ImSendmsgSinParamReq imSendmsgSinParamReq = new ImSendmsgSinParamReq();
            imSendmsgSinParamReq.setFrom_Account(cs.getPatientId() + "_" + LoginInfo.UserType.PATIENT + "_" + cs.getMedId());
            imSendmsgSinParamReq.setTo_Account(cs.getDoctorId() + "_" + LoginInfo.UserType.DOCTOR);
            imSendmsgSinParamReq.setSyncOtherMachine(2);
            imSendmsgSinParamReq.setCloudCustomData(String.valueOf(cs.getId()));
            TencentConstants.ImMsgPojo imMsgPojo = new TencentConstants.ImMsgPojo();
            tencentImMsgService.imSendmsgSymtem(imSendmsgSinParamReq, imMsgPojo.imMsgSet(TencentConstants.ImMsgCustom.PATIENT_PAY_PRES));
        }
    }

    /**
     * 问诊中处方订单支付未完成通知消息
     *
     * @param consultId
     * @param tencode
     */
    @Override
    public void consultPresPayTimeout(Integer consultId, String tencode) {
        ConsultSubscribe cs = getById(consultId);
        if (cs != null) {
            ImSendmsgSinParamReq imSendmsgSinParamReq = new ImSendmsgSinParamReq();
            imSendmsgSinParamReq.setFrom_Account(cs.getPatientId() + "_" + LoginInfo.UserType.PATIENT + "_" + cs.getMedId());
            imSendmsgSinParamReq.setTo_Account(cs.getDoctorId() + "_" + LoginInfo.UserType.DOCTOR);
            imSendmsgSinParamReq.setSyncOtherMachine(2);
            imSendmsgSinParamReq.setCloudCustomData(String.valueOf(cs.getId()));
            TencentConstants.ImMsgPojo imMsgPojo = new TencentConstants.ImMsgPojo();
            if (cs.getStatus() == ConsultConstants.Status.UNDERWAY) {
                tencentImMsgService.imSendmsgSymtem(imSendmsgSinParamReq, imMsgPojo.imMsgSet(TencentConstants.ImMsgCustom.PATIENT_PAY_PRES_TIMEOUT_2), tencode);
            } else if (ConsultConstants.Status.COMPLETE_ALL.contains(cs.getStatus())) {
                tencentImMsgService.imSendmsgSymtem(imSendmsgSinParamReq, imMsgPojo.imMsgSet(TencentConstants.ImMsgCustom.PATIENT_PAY_PRES_TIMEOUT_1));
            }
        }
    }


    /**
     * 查询医生在线问诊在线咨询待接诊数量
     *
     * @param doctorId
     * @return
     */
    @Override
    public ConsultUnReceiveCountRes queryConsultUnReceiveCountDoctor(Integer doctorId) {
        if (doctorId == null) {
            doctorId = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.DOCTOR).get().getId();
        }
        return getBaseMapper().queryConsultUnReceiveCountDoctor(doctorId);
    }

    @Override
    public void saveSymptom(ConsultSysmptomReq consultSysmptomReq) {
        ConsultSubscribe consultSubscribe = getById(consultSysmptomReq.getConsultId());
        if (consultSubscribe == null) {
            throw new ZekeException("问诊不存在");
        }
        LambdaUpdateWrapper<ConsultSubscribe> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ConsultSubscribe::getId, consultSysmptomReq.getConsultId()).set(ConsultSubscribe::getSymptoms, consultSysmptomReq.getSymptom());
        boolean flag = this.update(updateWrapper);
        if (!flag) {
            throw new ZekeException("保存失败");
        }
        //发送提交症状通知
//        ImSendmsgSinParamReq imSendmsgSinParamReq = new ImSendmsgSinParamReq();
//        imSendmsgSinParamReq.setFrom_Account(consultSubscribe.getDoctorId() + "_" + LoginInfo.UserType.DOCTOR);
//        imSendmsgSinParamReq.setTo_Account(consultSubscribe.getPatientId() + "_" + LoginInfo.UserType.PATIENT + "_" + consultSubscribe.getMedId());
//        imSendmsgSinParamReq.setSyncOtherMachine(1);
//        imSendmsgSinParamReq.setCloudCustomData(String.valueOf(consultSubscribe.getId()));
//        //TencentConstants.ImMsgCustom imMsgCustom = TencentConstants.ImMsgCustom.FSYMPTOM;
//        //tencentImMsgService.imSendmsgSymtem(imSendmsgSinParamReq, imMsgCustom);
//        TencentConstants.ImMsgPojo imMsgPojo = new TencentConstants.ImMsgPojo();
//        tencentImMsgService.imSendmsgSymtem(imSendmsgSinParamReq, imMsgPojo.imMsgSet(TencentConstants.ImMsgCustom.FSYMPTOM, consultSysmptomReq.getDiseaseName()));

    }

    @Override
    public String querySymptom(Integer consultId) {
        ConsultSubscribe consultSubscribe = this.getById(consultId);
        if (consultSubscribe != null) {

            return consultSubscribe.getSymptoms();
        }
        return "";
    }

    /**
     * 查询接诊数量
     *
     * @param docId
     * @return
     */
    @Override
    public Integer queryReceiveConsultCount(Integer docId) {
        if (docId == null) {
            docId = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.DOCTOR).get().getId();
        }
        QueryWrapper<ConsultSubscribe> qw = new QueryWrapper<>();
        qw.lambda().eq(ConsultSubscribe::getDoctorId, docId);
        qw.lambda().in(ConsultSubscribe::getStatus, ConsultConstants.Status.RECEIVE_CONSULT_ALL);
        return count(qw);
    }
}
